/*
 * @Author: your name
 * @Date: 2021-10-21 22:36:25
 * @LastEditTime: 2021-10-25 22:41:16
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \webrtc_easy_signal\proto.go
 */
package main

import (
	"encoding/json"
	"log"
	"sync"
)

type Request struct {
	Type int                    `json:"type"`
	Data map[string]interface{} `json:"data"`
}

const (
	REQ_LOGIN      = 1000
	REQ_INROOM     = 1001
	REQ_LEAVEROOM  = 1002
	REQ_CREATEROOM = 1003
	REQ_LISTROOM   = 1004
	REQ_SENDSDP    = 1005
	REQ_SENDCANDIDATE = 1006

	RESP_LOGIN      = 2000
	RESP_INROOM     = 2001
	RESP_LEAVEROOM  = 2002
	RESP_CREATEROOM = 2003
	RESP_LISTROOM   = 2004
	RESP_SENDSDP    = 2005
	RESP_SENDCANDIDATE = 2006
)

type Peer struct {
	Name string        // 用户名
	Ws   *WsConnection // websocket连接
	Room *Room         // 当前处在哪个房间
}

type Room struct {
	Name  string           // 房间名称
	ws    *WsConnection    // websocket连接
	Peers map[string]*Peer // 在房间里的节点
}

var gmapRoom sync.Map
var gmapUser sync.Map

func get_room_online(name string) *Room{
	room,ok := gmapRoom.Load(name)
	if ok{
		return room.(*Room)
	}
	return nil
}

func get_peers_online(name string) *Peer {
	peer, ok := gmapUser.Load(name)
	if ok {
		return peer.(*Peer)
	}
	return nil
}

func get_interface_string(v interface{}) string {
	ret, ok := v.(string)
	if ok {
		return ret
	}
	return ""
}
func ProtoUnconnect(ws *WsConnection){
	if nil == ws{
		return
	}
	foundname := ""
	gmapUser.Range(func(key, value interface{}) bool {
		if value.(*Peer).Ws == ws{
			foundname = value.(*Peer).Name
			if value.(*Peer).Room != nil{
				delete(value.(*Peer).Room.Peers, foundname)

				peers_in_room := map[string]interface{}{}
				for _,v := range value.(*Peer).Room.Peers{
					peers_in_room[v.Name] = true
				}
				for _,v := range  value.(*Peer).Room.Peers{
					v.Ws.SendPayload(RESP_LISTROOM,peers_in_room)	
				}
			}
		}
		return true
	})
	gmapUser.Delete(foundname)
	
}

func ProtoCallBack(ws *WsConnection, dat []byte) {
	if nil == ws {
		return
	}
	var payload Request
	e := json.Unmarshal(dat, &payload)
	if nil != e {
		log.Print(e.Error())
	}
	log.Print(payload)
	switch payload.Type {
	case REQ_LOGIN:
		name := get_interface_string(payload.Data["name"])
		if name != "" {
			if get_peers_online(name) != nil {
				log.Print("节点名重复")
				// todo 返回
				ws.SendPayload(RESP_LOGIN,map[string]interface{}{
					"status": -1,
					"data":"节点名重复",
				})				
				return
			}
			peer := new(Peer)
			peer.Name = name
			peer.Ws = ws
			gmapUser.Store(name, peer)
			ws.SendPayload(RESP_LOGIN,map[string]interface{}{
				"status":0,
				"data":"success",
			})
		}
	case REQ_INROOM:
		name := get_interface_string(payload.Data["name"])
		room_name := get_interface_string(payload.Data["room_name"])
		if (room_name != "") && (name != "") {
			// 不存在房间就创建房间
			if _, ok := gmapRoom.Load(payload.Data["room_name"]); !ok {

				newroom := new(Room)
				newroom.Name = payload.Data["room_name"].(string)
				gmapRoom.Store(payload.Data["room_name"], newroom)
				//
				if peer, ok := gmapUser.Load(payload.Data["name"]); ok {
					newroom.Peers = make(map[string]*Peer)
					newroom.Peers[payload.Data["name"].(string)] = peer.(*Peer)
				}
			} else {
				// 将该用户添加进房间
				peer := get_peers_online(name)
				peer.Room = get_room_online(room_name)
				peer.Room.Peers[name] = peer
			}
			room := get_room_online(room_name)
			peers_in_room := map[string]interface{}{}
			
			if nil != room{
				for _,v := range room.Peers{
					peers_in_room[v.Name] = true
				}
				for _,v := range room.Peers{
					v.Ws.SendPayload(RESP_LISTROOM,peers_in_room)	
				}
			}
		}
		break
	case REQ_CREATEROOM:

		break
	case REQ_LEAVEROOM:

		break
	case REQ_LISTROOM:
		// 显示room中其他成员
		name := get_interface_string(payload.Data["name"])
		peer := get_peers_online(name)
		if nil != peer{

		}
		room_name := get_interface_string(payload.Data["room_name"])
		room := get_room_online(room_name)
		peers_in_room := map[string]interface{}{}
		
		if nil != room{
			for _,v := range room.Peers{
				peers_in_room[v.Name] = true
			}
		}
		ws.SendPayload(RESP_LISTROOM,peers_in_room)
		break
	case REQ_SENDSDP:
		name := get_interface_string(payload.Data["name"])
		peer_name := get_interface_string(payload.Data["remote_name"])
		sdp :=  get_interface_string(payload.Data["sdp"])
		if((name == "") ||(peer_name == "")){
			return
		}
		peer_remote := get_peers_online(peer_name)
		if peer_remote != nil{
			peer_remote.Ws.SendPayload(RESP_SENDSDP,map[string]interface{}{
				"sdp":sdp,
				"remote_name":name,
			})
		}
		break
	case REQ_SENDCANDIDATE:	
		name := get_interface_string(payload.Data["name"])
		peer_name := get_interface_string(payload.Data["remote_name"])
		sdp :=  get_interface_string(payload.Data["candidate"])
		peer_remote := get_peers_online(peer_name)
		if peer_remote != nil{
			peer_remote.Ws.SendPayload(RESP_SENDCANDIDATE,map[string]interface{}{
				"candidate":sdp,
				"remote_name":name,
			})
		}
		break	
	}
}
